<?php
namespace xlx;

use Workerman\Events\EventInterface;
use \Connection\TcpBlockConnection;
use \Hprose\Future;

class Actor extends DispatchClient
{
    public $pid;
    public $alias=[];
    public $trap_exit;

 
    public static function create($fn/* yieldable($actor,$pid):void */)
    {
        //启动全局tcp并监听send/throw消息
        $event = self::getTcpReceiver();
        $actor = new self();
        $actor->pid = $pid =  self::getClientName()."@".uniqid();
        $actor->trap_exit = false;
        Future\co( $fn, $actor, $pid)->complete(function () use ($actor, $event) {
            self::$message[$actor->pid] = null;
            foreach ($actor->alias as $name => $bool) {
                $actor->unregister($name);
            }
            if ($event instanceof \Events\BlockSelect) {
                $event->break();
            }
        });
 
        if ($event instanceof \Events\BlockSelect && empty($event->loop)) {
            $event->loop();
        }
    }
    

    public function receive($fn = null/* function($data):bool */, $timeout = -1, $cb = null)
    {
        $defer = new Future;
        $defer->selectfn = $fn??function ($data) {
            return $data;
        };
        $defer->trap_exit = $this->trap_exit;
        if ($timeout>=0) {
            $event = Util::getEventLoop();
            $cb = $cb??function () {
                return true;
            };
            $event->add($timeout, EventInterface::EV_TIMER_ONCE, function () use ($defer, $cb) {
                $defer->resolve(\call_user_func($cb));
            });
        }
        return self::$message[$this->pid] = $defer;
    }
    public function trap_exit($bool)
    {
        $this->trap_exit=$bool;
    }
    public function self()
    {
        return $this->pid;
    }
    public function register($name/*alias*/)
    {
        if (empty($this->alias[$name])) {
            $this->alias[$name]=true;
            self::getTcpServer()->send(['register',$name,$this->pid]);//注册全局 端口时注销
        }
    }
    public function unregister($name/*alias*/)
    {
        unset($this->alias[$name]);
        self::getTcpServer()->send(['unregister',$name,$this->pid]);//立即注销
    }
    


    public static function send($pid/* pid | alias */, $data)
    {
        if (preg_match('/([\w\.:]+)@(\w+)/', $pid, $arr)) {
            list($_,$addr,$uniqid) = $arr;
            self::getTcpPeer($addr)->send(['send',$pid,$data]);
        } else {
            self::getTcpServer()->send(['send',$pid,$data]);
        }
    }
    public static function spawn($fn/*($args):throw?*/, ...$args)
    {
        self::getTcpServer()->send(['spawn',Util::encodeClosure($fn), $args ]);
    }
    public static function spawn_link($pid, $fn/*($args):throw?*/, ...$args)
    {
        self::getTcpServer()->send(['spawn',Util::encodeClosure($fn), $args, ['link'=>$pid] ]);
    }
    // public static function spawn_opt($opt/*[atomic,parallel,link]*/,$fn/*($args):throw?*/,...$args){
    //     self::getTcpServer()->send(['spawn',Util::encodeClosure($fn), $args, $opt ]);
    // }
}
 